/**
 * $Id: liveprReposition.js,v 1.3 2006/02/12 20:00:31 martin Exp $
 *
 * Drag n' drop repositioning
 * Most of this code is from FoxyTunes, see license below.
 * This script is part of the LivePR Firefox Extension.
 * It is licensed under the GPL. 
 * More details on <http://livepr.raketforskning.com/>.
 */

/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is FoxyTunes Mozilla Extension and Engine.
 * The Initial Developer of the Original Code is Alex Sirota <alex@elbrus.com>. 
 * Portions created by Alex Sirota are Copyright (C) 2004 Alex Sirota. All Rights Reserved.
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

function liveprInstallDragDropObserversForElementById(elementId, bInstall) {
   var elem = document.getElementById(elementId);
   if (elem == null) {
	//dump("\nAdding observer, cannot find element: " + elementId + "\n");
	return;
   }

   if (bInstall) {
  	elem.addEventListener("dragover", liveprOnTargetDragOver, false);
	elem.addEventListener("dragexit", liveprOnTargetDragExit, false);
	elem.addEventListener("dragdrop", liveprOnTargetDragDrop, false);
   } else {
  	elem.removeEventListener("dragover", liveprOnTargetDragOver, false);
	elem.removeEventListener("dragexit", liveprOnTargetDragExit, false);
	elem.removeEventListener("dragdrop", liveprOnTargetDragDrop, false);
   }
}

function liveprInstallUninstallDragDropObservers(bInstall) {
  liveprInstallDragDropObserversForElementById('status-bar', bInstall);

  // all the toolboxes:
  var toolboxes = document.getElementsByTagName('toolbox');
  for (var i = 0; i < toolboxes.length; i++) {
 	liveprInstallDragDropObserversForElementById(toolboxes[i].id, bInstall);
  }

  // liveprInstallDragDropObserversForElementById('navigator-toolbox', bInstall);
}

function liveprInstallDragDropObservers() {
   //dump("installing listeners for livepr");
   liveprInstallUninstallDragDropObservers(true);
}

function liveprUnInstallDragDropObservers() {
   liveprInstallUninstallDragDropObservers(false);
}


function liveprHasDropClass(className) {
  var classNames = className.split(" ");
  for (var i = 0; i < classNames.length; i++) {
	if (classNames[i].indexOf('livepr-drop-target-') != -1) {
		return true;
	}
  }
  return false;
}

function liveprRemoveDropClass(className) {
  var classNames = className.split(" ");

  if (classNames.length < 1) {
  	return className;
  }

  // see if the last class is LivePR drop class:
  if (classNames[classNames.length - 1].indexOf('livepr-drop-target-') != -1) {
	classNames.length--; // truncate the array
        if (classNames.length > 0) {
		className = classNames.join(" ");
	} else {
		className = "";
	}
  } 
  return className;
}

function liveprElementIsToolbarOrStatusbar(elem) {
  return (elem.localName == "toolbar") || (elem.localName == "statusbar") || (elem.localName == "menubar");
}

function liveprSetDropTargetMarker(node, bSet) {
  var target = node;
  var side = 'left';
  if (liveprElementIsToolbarOrStatusbar(node)) {
    target = node.lastChild;
    side = "right";
  }
  
  if (target == null) {
  	return;
  }

  if (bSet) {
	if (!liveprHasDropClass(target.className)) {
		var dropClassName = 'livepr-drop-target-' + side;
		target.className = target.className + " " + dropClassName;
		//dump("\n new Class " + target.className + "\n");
	}
  } else {
	target.className = liveprRemoveDropClass(target.className);
	//dump("\nRestored Class " + target.className + "\n");
  } 
}


function liveprOnTargetDragOver(event)
{
  nsDragAndDrop.dragOver(event, liveprTargetObserver);
}

function liveprOnTargetDragExit(event)
{
   if (gLivePRCurrentDropTarget != null) {
	   liveprSetDropTargetMarker(gLivePRCurrentDropTarget, false);
   }
}

function liveprOnTargetDragDrop(event)
{
  nsDragAndDrop.drop(event, liveprTargetObserver);
}

var liveprDragStartObserver =
{
  onDragStart: function (event, transferData, action) {
	liveprInstallDragDropObservers();
	transferData.data = new TransferData();
	transferData.data.addDataForFlavour('id/livepr-widget', 'livepr-status');
  }
}


var liveprTargetObserver =
{
  onDragOver: function (event, flavour, session)
  {
   //dump("over\n");
   var topElement = event.target;
   var target = event.target;
   while (topElement && !liveprElementIsToolbarOrStatusbar(topElement)) {
	      target = topElement;
	      topElement = topElement.parentNode;
   } 
   
   var previousDragItem = gLivePRCurrentDropTarget;

   if (liveprElementIsToolbarOrStatusbar(target)) {
	 gLivePRCurrentDropTarget = target;
   } else {
      	 var targetWidth = target.boxObject.width;
         var targetX = target.boxObject.x;

         gLivePRCurrentDropTarget = null;
         if (event.clientX > (targetX + (targetWidth / 2))) {
	        gLivePRCurrentDropTarget = target.nextSibling;
		//dump("\ncrossed\n");
        	if (gLivePRCurrentDropTarget == null) {
			  // last element in its parent, set target to parent
		          gLivePRCurrentDropTarget = topElement;
		}
      	 } else {
        	gLivePRCurrentDropTarget = target;
    	 }    
   }

   //dump("\nprev: " + previousDragItem.id + ", next: " + gLivePRCurrentDropTarget.id + "\n");
   if (previousDragItem && (gLivePRCurrentDropTarget != previousDragItem)) {
	liveprSetDropTargetMarker(previousDragItem, false);
   }
 
   if (gLivePRCurrentDropTarget.id.indexOf('livepr') == -1) { 
	   liveprSetDropTargetMarker(gLivePRCurrentDropTarget, true);
	   session.canDrop = true;
   } else {
   	   // cannot drop on myself: 
	   liveprSetDropTargetMarker(gLivePRCurrentDropTarget, false);
	   gLivePRCurrentDropTarget = null;
	   session.canDrop = false;
   }
  },
 
  onDragExit: function (event, session) 
  {
	//dump("exit\n");
  },

  onDrop: function (event, dropData, session)
  {
	//dump("drop\n");
	liveprUnInstallDragDropObservers();
        if (gLivePRCurrentDropTarget == null) {
		return; 
	}
        liveprSetDropTargetMarker(gLivePRCurrentDropTarget, false);
    
	var draggedItemId = dropData.data;
	// sanity, should never happen:
	if (gLivePRCurrentDropTarget.id == draggedItemId) {
	      	return;
	}

	var topElement = event.target;
        while (topElement && !liveprElementIsToolbarOrStatusbar(topElement)) {
	      topElement = topElement.parentNode;
        }

	// save the new settings:
	gLivePRParentElementID = topElement.id;
	gLivePRInsertBeforeElementId = gLivePRCurrentDropTarget.id;

	// for the case when the "insert before" element is a dynamic one, remember the 
	// "insert after" element
	if (gLivePRCurrentDropTarget.previousSibling) {	
	 	gLivePRInsertAfterElementId = gLivePRCurrentDropTarget.previousSibling.id;
	}
        //dump("writing prefs");
	liveprSavePreferences();
        //dump("setting pos");	
	liveprSetLivePRPosition();

	//dump("\nInserted to: " + topElement.id + ", before " + gLivePRCurrentDropTarget.id + "\n");
	gLivePRCurrentDropTarget = null;
  },
  
  
  getSupportedFlavours: function ()
  {
	var flavours = new FlavourSet();
	flavours.appendFlavour("id/livepr-widget");
	return flavours;
  }
}


function liveprRenameTagName(elem, newTagName) {
	var newElem = document.createElement(newTagName);

	// copy all the attributes of the element
	for (var i=0; i < elem.attributes.length; i++) {
		newElem.setAttribute(elem.attributes[i].nodeName, elem.attributes[i].nodeValue);
	}

	// move all the children
	var children = elem.childNodes;
	for (var i=children.length-1; i >=0 ; i--) {
        var currentNode = children[i];
		elem.removeChild(currentNode);
		newElem.insertBefore(currentNode, newElem.firstChild);
	} 

  	return newElem;	
}

function liveprSetLivePRPosition() {
    	if ((gLivePRParentElementID == '') ||
		(gLivePRInsertBeforeElementId == '')) {
			// nothing's set, return
			return;
	}

	var liveprWidget = document.getElementById('livepr-status');

	var parentElement = document.getElementById(gLivePRParentElementID);
	if (parentElement == null) {
		return;
	}
	//dump("\nParent element: " + gLivePRParentElementID + "\n");

	var insertBeforeElement = document.getElementById(gLivePRInsertBeforeElementId);
	var insertAfterElement = document.getElementById(gLivePRInsertAfterElementId);

	if ((insertBeforeElement == null) && (insertAfterElement == null)) {
		return;
	}

	//dump("\nInsert before element: " + gLivePRInsertBeforeElementId + "\n");
	//dump("\nInsert after element: " + gLivePRInsertAfterElementId + "\n");

	var oldParentNode = liveprWidget.parentNode;

	liveprWidget.parentNode.removeChild(liveprWidget);

	try {
		// make LivePR toolbaritem and not statubarpanel if needed:
		if ((parentElement.localName == 'toolbar') && (liveprWidget.localName == 'statusbarpanel')) {
			liveprWidget = liveprRenameTagName(liveprWidget, 'toolbaritem');
		}

		// make LivePR statusbarpanel and not toolbaritem if needed:
		if ((parentElement.localName == 'statusbar') && (liveprWidget.localName == 'toolbaritem')) {
			liveprWidget = liveprRenameTagName(liveprWidget, 'statusbarpanel');
		}

		// convention, if the parent equals insertbefore, insert as last
		if (parentElement != insertBeforeElement) {
			if (insertBeforeElement) {
				parentElement.insertBefore(liveprWidget, insertBeforeElement);
			} else {
				//dump('insert before failed try inserting after ' + gLivePRInsertAfterElementId + '\n');
				if (insertAfterElement.nextSibling) {
					parentElement.insertBefore(liveprWidget, insertAfterElement.nextSibling);
				} else {
					parentElement.appendChild(liveprWidget);
				}
			}
		} else {
			parentElement.appendChild(liveprWidget);
		}

	} catch (err) {
		//dump("\nCouldn't reposition LivePR: " + err + "\n");
		oldParentNode.appendChild(liveprWidget);
	}
}

// the current drop target:
var gLivePRCurrentDropTarget = null;
